//
// Created by bill3000 on 2/10/21.
// Usage: To use the Queue, call Queue::get_instance, and
// after finishing using it, call Queue::dispose() to free resources
//

#include <sys/msg.h>
#include <sys/ipc.h>

#include "queue.hpp"
#include "../log/logger.hpp"

Queue* Queue::instance = nullptr;

Queue* Queue::get_instance() {
    if (instance == nullptr)
        instance = new Queue();
    return instance;
}

Queue::Queue() {
    key_t key;

    key = ftok("/intelli/message/m01",2222);
    id_01 = msgget(key,IPC_CREAT | 0666);
    key = ftok("/intelli/message/m02",2233);
    id_02 = msgget(key,IPC_CREAT | 0666);
    key = ftok("/intelli/message/m03",2244);
    id_03 = msgget(key,IPC_CREAT | 0666);
    key = ftok("/intelli/message/m04",2255);
    id_04 = msgget(key,IPC_CREAT | 0666);

    if ((id_01 <= -1) || (id_02 <= -1) || (id_03 <= -1) || (id_04 <= -1)) {
        LOG(FATAL, "Cannot create message queue !");
        exit(1);
    }
}

int Queue::send_message(int queue, Message *message) const {
    int id;
    if (queue == M01) id = id_01;
    else if (queue == M02) id = id_02;
    else if (queue == M03) id = id_03;
    else if (queue == M04) id = id_04;
    else id = -1;
    if (id == -1) {
        LOG(ERROR, "Queue type parameter error !");
        return -1;
    }

    if(msgsnd(id,(void *)message, sizeof(Event),0) < 0) {
        LOG(ERROR, strerror(errno));
        return -1;
    }

    return 0;
}

int Queue::receive_message(int queue, Message *message, long mtype) const {
    int id;

    if (queue == M01) id = id_01;
    else if (queue == M02) id = id_02;
    else if (queue == M03) id = id_03;
    else if (queue == M04) id = id_04;
    else id = -1;

    if (id == -1) {
        LOG(ERROR, "Queue type parameter error !");
        return -1;
    }

    if(msgrcv(id,(Message *)message,sizeof(Event),mtype,0) < 0) {
        LOG(ERROR, strerror(errno));
        return -1;
    }

    return 0;
}

void Queue::dispose() {
    delete instance;
}

Queue::~Queue() {
    if (instance != nullptr) {
        msgctl(id_01, IPC_RMID, nullptr);
        msgctl(id_02, IPC_RMID, nullptr);
        msgctl(id_03, IPC_RMID, nullptr);
        msgctl(id_04, IPC_RMID, nullptr);
        instance = nullptr;
    }
}
